
require "lfs"

local sourcedir,headerdir = ...

if not (sourcedir and headerdir) then
    error('expecting two arguments (source dir and generated header dir)')
end
-- strip trailing slashes
if sourcedir:sub(-1):match"[/\\]" then
    sourcedir = sourcedir:sub(1,-2)
end
if headerdir:sub(-1):match"[/\\]" then
    headerdir = headerdir:sub(1,-2)
end
local dirs = {sourcedir}

local old_lastupdated = loadfile(headerdir .. "/__update_data.lua")
old_lastupdated = old_lastupdated and old_lastupdated() or {}

local lastupdated = {}

local dots = {["."] = 1, [".."] = 1}

local any_changes = false
local dirpaths = {}

local deletions = {}

for oldpath in pairs(old_lastupdated) do
    if not lfs.attributes(sourcedir .. "/" .. oldpath) then
        os.remove(headerdir .. "/" .. oldpath:gsub("%.lua$", ".h"))
    end
end

while dirs[1] do
    local nextdirs = {}
    
    for _,dir in ipairs(dirs) do
        for child in lfs.dir(dir) do
            local path = dir .. "/" .. child
            local croppedpath = path:sub(#sourcedir+2)
            local attrs = lfs.attributes(path)
            if attrs.mode == 'directory' and not dots[child] then
                dirpaths[#dirpaths+1] = croppedpath
                nextdirs[#nextdirs+1] = path
            elseif attrs.mode == 'file' and child:match("%.lua$") then
                lastupdated[croppedpath] = attrs.modification
                if old_lastupdated[croppedpath] ~= attrs.modification then
                    any_changes = true
                end
            end
        end
    end
    
    dirs = nextdirs
end

if not any_changes then
    return
end

for _,dirpath in ipairs(dirpaths) do
    local headerpath = headerdir .. "/" .. dirpath
    if lfs.attributes(headerpath, "mode") ~= 'directory' then
        assert(lfs.mkdir(headerpath))
    end
end

local file = io.open(headerdir .. "/__update_data.lua","w")
file:write "-- Autogenerated\n"
file:write "return {\n"
for k,v in pairs(lastupdated) do
    file:write( ("\t[%q] = %d;\n"):format(k,v) )
end
file:write "}"
file:close()

local tobytearray do
    local numtab={}
    for i = 0,255 do
        numtab[string.char(i)] = ("%3d,"):format(i)
    end
    function tobytearray(str)
        return str:gsub(".", numtab):gsub(("."):rep(80), "%0\n")
    end
end

local compiled = {}
for path,timestamp in pairs(lastupdated) do
    if timestamp ~= old_lastupdated[k] then
        local chunk_name = "chunk_" .. path:gsub("%.lua$",""):gsub("%W","_")
        local revert = lfs.currentdir()
        lfs.chdir(sourcedir)
		local src do
			local srcfile = io.open(path, 'rb')
			src = srcfile:read('*a')
			srcfile:close()
		end
        local d = assert(loadstring(src, 'SYSTEM:' .. path))
        lfs.chdir(revert)
        d = string.dump(d)
        local headerpath = headerdir .. "/" .. path:gsub("%.lua$", ".h")
        local header = assert(io.open(headerpath, "w"))
        header:write("// Autogenerated\n")
        header:write("static const char ", chunk_name, "[] = {\n", tobytearray(d), "\n};\n")
        header:close()
    end
end

--[[
local masterheader = io.open("chunks.h","w")
masterheader:write("// Autogenerated\n")
masterheader:write("#ifndef CHUNKS_H_INCLUDED\n#define CHUNKS_H_INCLUDED\n\n")
for path in pairs(lastupdated) do
    local headerpath = headerdir .. "/" .. path:gsub("%.lua$", ".h")
    masterheader:write( ("#include %q\n"):format(headerpath) )
end
masterheader:write("\n#endif\n")
masterheader:close()
--]]